﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using SDT.CodeSystem;
using SDT.CrawlSystem.Servers.Filters;
using SDT.DataService.Services;

namespace SDT.CrawlSystem.Servers
{
    /// <summary>
    /// Written by TungNX
    /// </summary>
    public sealed partial class UrlLoader
    {
        #region Page - Filter condition
        private int pid = 0;
        public int PID
        {
            get { return pid; }
        }
        #endregion

        #region nRetry - Filter condition
        private int retryFrom = 0;
        public int RetryFrom
        {
            get { return retryFrom; }
        }
        private int retryTo = 0;
        public int RetryTo
        {
            get { return retryTo; }
        } 
        #endregion

        #region Id - Filter condition
        private int fromId = 0;
        public int FromId
        {
            get { return fromId; }
        }
        private int toId = 0;
        public int ToId
        {
            get { return toId; }
        } 
        #endregion

        #region Status - Filter condition
        private IList<Status> StatusList = new List<Status>();
        public string StrStatus
        {
            get
            {
                var b = new StringBuilder();
                foreach (var s in StatusList)
                {
                    if (s == Status.NA)
                        return "";
                    b.Append((int)s).Append(';');
                }
                return b.ToString();
            }
        } 
        #endregion

        #region Allow Tag
        private string allowTag = string.Empty;
        public string AllowTag
        {
            get
            {
                return allowTag;             
            }
        
        }

        private string removeTag = string.Empty;
        public string RemoveTag
        {
            get { return removeTag; }
            set { removeTag = value; }
        }

        private string removeAttribute = string.Empty;
        public string RemoveAttribute
        {
            get { return removeAttribute; }
            set { removeAttribute = value; }
        }
        
        #endregion

        #region Index - Filter condition
        private int pageSize = 20;
        public int PageSize
        {
            get { return pageSize; }
        }
        private int pageNo = 1;
        public int CurrentPage
        {
            get { return pageNo; }
        } 
        #endregion

        #region Statistics information
        private int totalPages = 0;
        public int TotalPages
        {
            get { return totalPages; }
        }

        private int totalUrls = 0;
        public int TotalUrls
        {
            get { return totalUrls; }
            set { totalUrls = value; }
        }
        #endregion

        private Encoding enc = Encoding.UTF8;
        public Encoding Enc
        {
            get { return enc; }
        }

        #region Analysers - Html extractors
        private IFilter hFilter = null;
        public IFilter HFilter
        {
            get { return hFilter; }
        }
        private IFilter tFilter = null;
        public IFilter TFilter
        {
            get { return tFilter; }
        }

        private IFilter lFilter = null;

        public IFilter LFilter
        {
            get { return lFilter; }
           
        }

        private IDateFilter dFilter = null;
        public IDateFilter DFilter
        {
            get { return dFilter; }
        }

        private IFilter conFilter = null;
        public IFilter ConFilter
        {
            get { return conFilter; }
        }

       

        #endregion

        #region Data fields
        private string prefix = "";
        public string Prefix
        {
            get { return prefix; }
        }

        private ICity city = null;
        public ICity City
        {
            get { return city; }
        }

        private IDistrict district = null;
        public IDistrict District
        {
            get { return district; }
        }

      
        #endregion

        #region Data Service

        private PageService svPage = new PageService();
        #endregion

        #region Constructors
        public UrlLoader(int pid, XmlNode node, UrlLoader uFilter, IFilter hFilter,
            IFilter tFilter, IDateFilter dFilter, IFilter conFilter, 
            Encoding enc)
        {
            #region Assign analysers
            this.hFilter = hFilter;
            this.tFilter = tFilter;
            this.dFilter = dFilter;
            this.conFilter = conFilter;
            #endregion

            #region Assign filter conditions
            this.pid = pid;
            pageSize = uFilter.pageSize;
            fromId = uFilter.fromId;
            toId = uFilter.toId;

            retryFrom = uFilter.retryFrom;
            retryTo = uFilter.retryTo;

            StatusList = new List<Status>(uFilter.StatusList);
            #endregion

            #region Assign remove tag
            this.allowTag = uFilter.allowTag;
            this.removeTag = uFilter.removeTag;
            this.removeAttribute = uFilter.removeAttribute;
            #endregion

            prefix = uFilter.prefix;

            this.enc = enc;

            #region Get override filter condition (if have)
            if (node != null)
            {
                if (node.Attributes["Size"] != null)
                    pageSize = Convert.ToInt32(node.Attributes["Size"].Value);
                if (node.Attributes["Prefix"] != null)
                    prefix = node.Attributes["Prefix"].Value;

                var n = node.SelectSingleNode("Id");
                if (n != null)
                {
                    if (n.Attributes["From"] != null)
                        fromId = Convert.ToInt32(n.Attributes["From"].Value);
                    if (n.Attributes["To"] != null)
                        toId = Convert.ToInt32(n.Attributes["To"].Value);
                }

                n = node.SelectSingleNode("Retry");
                if (n != null)
                {
                    if (n.Attributes["From"] != null)
                        retryFrom = Convert.ToInt32(n.Attributes["From"].Value);
                    if (n.Attributes["To"] != null)
                        retryTo = Convert.ToInt32(n.Attributes["To"].Value);
                }

                n = node.SelectSingleNode("Status");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    StatusList.Clear();
                    var status = n.InnerText.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var s in status)
                        StatusList.Add(FromString(s));
                }

                n = node.SelectSingleNode("AllowTag");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    allowTag = n.InnerText;
                }

                n = node.SelectSingleNode("RemoveTag");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    removeTag = n.InnerText;
                }

                n = node.SelectSingleNode("RemoveAttribute");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    removeAttribute = n.InnerText;
                }
            }
            #endregion
        }
        public UrlLoader(int pid, XmlNode node, UrlLoader uFilter, IFilter hFilter,
           IFilter tFilter, IFilter lFilter,  IDateFilter dFilter, IFilter conFilter,
          Encoding enc)
        {
            #region Assign analysers
            this.hFilter = hFilter;
            this.tFilter = tFilter;
            this.lFilter = lFilter;
            this.dFilter = dFilter;
            this.conFilter = conFilter;           
            #endregion

            #region Assign filter conditions
            this.pid = pid;
            pageSize = uFilter.pageSize;
            fromId = uFilter.fromId;
            toId = uFilter.toId;

            retryFrom = uFilter.retryFrom;
            retryTo = uFilter.retryTo;

            StatusList = new List<Status>(uFilter.StatusList);
            #endregion

            #region Assign remove tag
            this.allowTag = uFilter.allowTag;
            this.removeTag = uFilter.removeTag;
            this.removeAttribute = uFilter.removeAttribute;
            #endregion

            prefix = uFilter.prefix;

            this.enc = enc;

            #region Get override filter condition (if have)
            if (node != null)
            {
                if (node.Attributes["Size"] != null)
                    pageSize = Convert.ToInt32(node.Attributes["Size"].Value);
                if (node.Attributes["Prefix"] != null)
                    prefix = node.Attributes["Prefix"].Value;

                var n = node.SelectSingleNode("Id");
                if (n != null)
                {
                    if (n.Attributes["From"] != null)
                        fromId = Convert.ToInt32(n.Attributes["From"].Value);
                    if (n.Attributes["To"] != null)
                        toId = Convert.ToInt32(n.Attributes["To"].Value);
                }

                n = node.SelectSingleNode("Retry");
                if (n != null)
                {
                    if (n.Attributes["From"] != null)
                        retryFrom = Convert.ToInt32(n.Attributes["From"].Value);
                    if (n.Attributes["To"] != null)
                        retryTo = Convert.ToInt32(n.Attributes["To"].Value);
                }

                n = node.SelectSingleNode("Status");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    StatusList.Clear();
                    var status = n.InnerText.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var s in status)
                        StatusList.Add(FromString(s));
                }

                n = node.SelectSingleNode("AllowTag");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    allowTag = n.InnerText;                
                }

                n = node.SelectSingleNode("RemoveTag");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    removeTag = n.InnerText;
                }

                n = node.SelectSingleNode("RemoveAttribute");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    removeAttribute = n.InnerText;
                }

            }
            #endregion
        }

        public UrlLoader(XmlNode node)
        {
            #region Get default filter-conditions
            pageSize = Convert.ToInt32(node.Attributes["Size"].Value);
            prefix = node.Attributes["Prefix"].Value;

            var n = node.SelectSingleNode("Id");
            fromId = Convert.ToInt32(n.Attributes["From"].Value);
            toId = Convert.ToInt32(n.Attributes["To"].Value);

            n = node.SelectSingleNode("Retry");
            retryFrom = Convert.ToInt32(n.Attributes["From"].Value);
            retryTo = Convert.ToInt32(n.Attributes["To"].Value);

            n = node.SelectSingleNode("Status");
            var status = n.InnerText.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var s in status)
                StatusList.Add(FromString(s)); 

             n = node.SelectSingleNode("AllowTag");
                if (n != null && n.InnerText.Trim().Length > 0)
                {
                    allowTag = n.InnerText;                
                }

            n = node.SelectSingleNode("RemoveTag");
            if (n != null && n.InnerText.Trim().Length > 0)
            {
                removeTag = n.InnerText;
            }

            n = node.SelectSingleNode("RemoveAttribute");
            if (n != null && n.InnerText.Trim().Length > 0)
            {
                removeAttribute = n.InnerText;
            }
            #endregion
        } 
        #endregion

        #region URL - Enumerator
        public bool EOF
        {
            get
            {
                lock (this)
                    return totalPages < pageNo;
            }
        }

        public void Refresh()
        {
            lock (this)
                if (EOF)
                {
                    totalPages = 0;
                    pageNo = 1;                  
                    totalPages =  (svPage.CountList(this)+ pageSize - 1) / pageSize;
                }
        }

        private void NextPage() { pageNo++; }

        public IList<WebWorkUnit> RetrieveWorkUnits()
        {
            lock (this)
                if (EOF)
                    return new List<WebWorkUnit>();
                else
                {  
                    var l = svPage.GetSelectList(this);
                    totalUrls += l.Count;
                    NextPage();
                    return l;
                }
        }
        #endregion
    }
}